package com.yucc.girlimages.ui.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
/**
* 一个支持多点触摸放大缩小的图片组件
* @author YPF
*@version 1.0
*@描述 支持双点触摸缩放的图片组件，必须预先定义画布和图片大小
*构造函数{ ScaleImageView(Context context,int x,int y)},数据接入点为setImageBitmap,暂时只支持Bitmap数据，
*组件暂时适合于类创建，还未在android xml上创建过.
*/
public class ScaleImageView extends ImageView {
        /*************************************
         * parameter
         */
        //没有操作的状态
        static final int NONE=0;
        //拖动
        static final int DRAG=1;
        //缩放
        static final int ZOOM=2;
        //缩小ing
        static final int SMALLER=3;
        //放大ing
        static final int BIGGER=4;
        //关闭缩放动画
        static final int OPENSCALE=1;
        //关闭移动动画
        static final int OPENTRANS=2;
        //当前的事件
        private int mode=NONE;
        //两触摸点的距离
        private float beforeLength;
        private float afterLength;
        //缩放比率,这个应该是根据两指的移动速度来判断的
        private float scale=0.1f;
        /* 拖动变量一坨坨 */
        private int screenW;
        private int screenH;
        private int start_x;
        private int start_y;
        private int stop_x;
        private int stop_y;
        private TranslateAnimation trans;
        /*Bitmap的宽高 */
        private int bmWidth;
        private int bmHeight;
        /*处理超出边界的动画*/
        private Bitmap bitmap;
        private float maxScale=4.0f;
        private float minScale=1.0f;
        /*记录初始动画，用于图片回弹 */
        private int startWidth=0;
        private float piovtX=0.5f;
        private float piovtY=0.5f;
        //默认开启所有动画
        private int animSwicth=OPENSCALE|OPENTRANS;
        //中心点
        private float[] center;
        /*************************************
         * 构造函数
         * @param context 图片所在的画布
         */
        public ScaleImageView(Context context) {
                super(context);
        }
        
        public ScaleImageView(Context context, AttributeSet attrs) {
			super(context, attrs);
			screenW = getWidth() ;
			screenH = getHeight() ;
		}


		/**
         * 关联容器的构造函数
         * @param context 容器画布
         * @param x 容器的宽
         * @param y 容器的高
         */
        public ScaleImageView(Context context,int x,int y){
                super(context);
                this.setPadding(0, 0, 0, 0);//设置图片填充
                screenW=x;
                screenH=y;
        }
        /**
         * 重写setImageBitmap通过加载外部Bitmap的方式初始化内部bitmap
         * [入口方法]
         */
        @Override
        public void setImageBitmap(Bitmap bm) {
                // TODO Auto-generated method stub
                super.setImageBitmap(bm);
                startWidth=0;
                bmWidth=bm.getWidth();
                bmHeight=bm.getHeight();
                if(bitmap!=null && !bitmap.isRecycled())
                        bitmap.recycle();
                bitmap=bm;
        }
        /**
         * 初始化外接框（view），计算初始化长宽
         */
        @Override
        protected void onLayout(boolean changed, int left, int top, int right,
                        int bottom) {
                // TODO Auto-generated method stub
                super.onLayout(changed, left, top, right, bottom);
                if(startWidth==0)
                        startWidth=right-left;
                setRect();//设置图片大小等于容器
                animSwicth=0;
                onRebound();//超范围处理
                animSwicth=OPENSCALE|OPENTRANS;
        }
        /**
         * 处理多点触摸时图片变化
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction() & MotionEvent.ACTION_MASK) {
                /* 当屏幕检测到有手指按下之后就触发到这个事件*/
                case MotionEvent.ACTION_DOWN:
                        mode=DRAG;
                        //getRawX是触摸点相对于屏幕的坐标，getX是触摸点相对于按钮的坐标
                        stop_x=(int)event.getRawX();
                        stop_y=(int)event.getRawY();
                        start_x=(int)event.getX();
                        start_y=stop_y-getTop();//这里其实可以用getY代替 但不知道效果如何
                        if(event.getPointerCount()==2)
                                beforeLength=spacing(event);
                        break;
                /*当屏幕检测到有多个手指同时按下之后，就触发了这个事件*/
                case MotionEvent.ACTION_POINTER_DOWN:
                        /** 根据中心点和view边框的比率来算缩放边框移动的比率*/
                        center=centerPoint(event);
                        piovtX=center[0]/getWidth();
                        piovtY=center[1]/getHeight();
                        
                        center[0]=(center[0]/getWidth())*scale;
                        center[1]=(center[1]/getHeight())*scale;
                        if(spacing(event)>10f){
                                mode=ZOOM;
                                beforeLength=spacing(event);
                        }
                        break;
                /*重置掉多点模式和记录的距离等等*/
                case MotionEvent.ACTION_POINTER_UP:
                        mode=NONE;
                        break;
                /*处理单点模式，计算移动距离，设置LayoutParams */
                case MotionEvent.ACTION_UP:
                        mode=NONE;
                        setRect();
                        if(!onReScale())
                                onRebound();
                        break;
                /** 多点模式时，计算两点距离，通过与第一次的计算值的比例，得到缩放比例
                                单点模式时，计算移动距离，设置LayoutParams*/
                case MotionEvent.ACTION_MOVE:
                        /*拖动处理*/
                        if(mode==DRAG){
                            this.setPosition(stop_x - start_x, stop_y - start_y, stop_x  
                                          + this.getWidth() - start_x,  
                                          stop_y - start_y + this.getHeight());  
//                                 this.setPosition(stop_x - start_x+(int)event.getX(), stop_y - start_y+(int)event.getY(), stop_x  
//                                          + this.getWidth() - start_x+(int)event.getX(),  
//                                          stop_y - start_y + this.getHeight()+(int)event.getY());  
                stop_x = (int) event.getRawX();  
                stop_y = (int) event.getRawY();  
                        }
                        /*缩放处理*/
                        if(mode==ZOOM){
                            if (spacing(event) > 10f) {  
                                        afterLength = spacing(event);  
                                        float gapLenght = afterLength - beforeLength;  
                                        if (gapLenght == 0) {  
                                                break;  
                                        } else if (Math.abs(gapLenght) > 5f) {  
                                                 if (gapLenght > 0) {  
                                                         this.setScale(scale, BIGGER);  
                                                 } else {  
                                                         this.setScale(scale, SMALLER);  
                                                 }  
                                                 beforeLength = afterLength;  
                                        }  
                               } 
                        }
                        break;
                default:
                        break;
                }
                return true;
        }
        /**
         * 实现拖动处理计算重绘边框位置
         * @param left
         * @param top
         * @param right
         * @param bottom
         */
        private void setPosition(int left, int top, int right, int bottom) {  
                // TODO Auto-generated method stub
                this.layout(left, top, right, bottom);  
        }
        /**
         * 设置imageview大小等于显示内容的大小
         */
        private void setRect(){
                float scale=Math.min((float)getWidth()/(float)bmWidth, (float)getHeight()/(float)bmHeight);
                int w=(int)((float)bmWidth*scale)+1;
                int h=(int)((float)bmHeight*scale)+1;
                
                int l=getLeft();
                int t=getTop();
                int r=l+w;
                int b=t+h;
//                layout(l, t, r, b);
        }
        /**
         * 处理缩放回弹
         * @return
         */
        public boolean onReScale(){
                  float scaleX = 1f;  
                  float scaleY = 1f;  
                  int width=getWidth();  
                  int height=getHeight();  
                  int l,t,r,b;  
                  if (center==null)
                          return false;  
                  if (getWidth() > startWidth * maxScale) {  
                           while(getWidth()>startWidth * maxScale){  
                                   l = this.getLeft() + (int) (center[0] * this.getWidth());  
                                   t = this.getTop() + (int) (center[1] * this.getHeight());  
                                   r = this.getRight() - (int) ((scale - center[0]) * this.getWidth());  
                                   b = this.getBottom()- (int) ((scale - center[1]) * this.getHeight());  
                                   this.setFrame(l, t, r, b);  
                           }  
                           scaleX=(float)width/(float)getWidth();  
                           scaleY=(float)height/(float)getHeight();  
                  }  
                  if (getWidth() < startWidth * minScale) {  
                           while(getWidth() < startWidth * minScale){  
                                   l = this.getLeft() - (int) (center[0] * this.getWidth());  
                                   t = this.getTop() - (int) (center[1] * this.getHeight());  
                                   r = this.getRight() + (int) ((scale - center[0]) * this.getWidth());  
                                   b = this.getBottom()+ (int) ((scale - center[1]) * this.getHeight());  
                                   this.setFrame(l, t, r, b);  
                           }  
                           scaleX=(float)width/(float)getWidth();  
                           scaleY=(float)height/(float)getHeight();  
                  }  
                    
                  if (scaleX == 1f && scaleY == 1f)  
                          return false;  
                  if((animSwicth&OPENSCALE)==0){  
                           setRect();  
                           onRebound();  
                           return true;  
                  }  
                  ScaleAnimation scaleanim = new ScaleAnimation(scaleX, 1f, scaleY, 1f,  
                            ScaleAnimation.RELATIVE_TO_SELF, piovtX,  
                            ScaleAnimation.RELATIVE_TO_SELF, piovtY);  
                          scaleanim.setDuration(300);  
                          scaleanim.setInterpolator(new AccelerateInterpolator());  
                          scaleanim.setAnimationListener(new AnimationListener() {  
                                   @Override  
                                   public void onAnimationStart(Animation paramAnimation)
                                   {}  
                                   @Override  
                                   public void onAnimationRepeat(Animation paramAnimation)
                                   {}  
                                   @Override  
                                   public void onAnimationEnd(Animation paramAnimation) {  
                                            setRect();  
                                            onRebound();  
                                   }                       
                          });  
                  this.startAnimation(scaleanim);  
                  return true;  
        }
        /**
         * 处理超范围回弹
         */
        public void onRebound(){
                 /* 判断是否超出范围 并处理 */  
                  int disX = 0,  
                  disY = 0;  
                  if (getHeight() < screenH) {  
                          disY = (screenH - getHeight()) / 2 - getTop();  
                  }  
                  if (getWidth() < screenW) {  
                          disX = (screenW - getWidth()) / 2 - getLeft();  
                  }  
                  if (getHeight() >= screenH) {  
                           if (getTop() > 0)  
                                   disY = -getTop();  
                           if (getBottom() < screenH)  
                                   disY = screenH - getBottom();  
                  }  
                  if (getWidth() >= screenW) {  
                          if (getLeft() > 0)  
                                  disX = -getLeft();  
                          if (getRight() < screenW)  
                                   disX = screenW - getRight();  
                  }
                //开始回弹  
                 rebound(disX, disY);  
        }
        /**
         * 处理移动回弹
         * @param disX x偏移
         * @param disY y偏移
         */
        public void rebound(int disX, int disY){
//                this.layout(getLeft() + disX, getTop() + disY, getLeft() + disX  
//                            + getWidth(), getTop() + disY + getHeight());  
                          if((animSwicth&OPENTRANS)==0)  
                           return;  
                          trans = new TranslateAnimation(-disX, 0, -disY, 0);  
                          trans.setInterpolator(new AccelerateInterpolator());  
                          trans.setDuration(300);  
                          this.startAnimation(trans);  
        }
        /**
         * 处理缩放
         * @param temp 缩放比率
         * @param flag 缩放类型
         */
        private void setScale(float temp, int flag){
                 int l = 0, t = 0, r = 0, b = 0;  
                  if (flag == BIGGER) {  
                           l = this.getLeft() - (int) (center[0] * this.getWidth());  
                           t = this.getTop() - (int) (center[1] * this.getHeight());  
                           r = this.getRight() + (int) ((scale - center[0]) * this.getWidth());  
                           b = this.getBottom()+ (int) ((scale - center[1]) * this.getHeight());  
                  } else if (flag == SMALLER) {  
                           l = this.getLeft() + (int) (center[0] * this.getWidth());  
                           t = this.getTop() + (int) (center[1] * this.getHeight());  
                           r = this.getRight() - (int) ((scale - center[0]) * this.getWidth());  
                           b = this.getBottom()- (int) ((scale - center[1]) * this.getHeight());  
                  }  
                  this.setFrame(l, t, r, b);  
        }
        /**
         * 清除Image里的bitmap
         */
        public void recycle(){
                setImageBitmap(null);
                if(bitmap!=null&&!bitmap.isRecycled())
                        bitmap.recycle();
        }
        /**
         * 计算两点间距离
         * @param event 手指点击屏幕事件
         * @return 计算后的距离值
         */
        private float spacing(MotionEvent event){
                float x=event.getX(0)-event.getX(1);
                float y=event.getY(0)-event.getY(1);
                return FloatMath.sqrt(x*x+y*y);
        }
        /**
         * 计算两指间的中心点
         * @param event 手指在屏幕产生的事件
         * @return 返回计算后的中心点
         */
        private float[] centerPoint(MotionEvent event){
                float[] center=new float[2];
                float x=event.getX(0);
                float y=event.getY(0);
                float x1=event.getX(1);
                float y1=event.getY(1);
                center[0]=(x+x1)/2;
                center[1]=(y+y1)/2;
                return center;
        }
}
